package com.xu.sso.web.service.impl;

import com.xu.sso.core.config.SSOConfig;
import com.xu.sso.core.enums.ErrorMessage;
import com.xu.sso.core.exception.SSOException;
import com.xu.sso.core.model.AppPathRole;
import com.xu.sso.core.model.BaseResponse;
import com.xu.sso.core.utils.ExceptionUtil;
import com.xu.sso.core.utils.RedisUtil;
import com.xu.sso.db.model.base.App;
import com.xu.sso.db.model.base.AppRole;
import com.xu.sso.db.model.base.Resources;
import com.xu.sso.db.service.AppDBService;
import com.xu.sso.db.service.ResourcesDBService;
import com.xu.sso.db.service.RoleDBService;
import com.xu.sso.web.model.request.AddResRoleRequest;
import com.xu.sso.web.model.request.AddResourcesRequest;
import com.xu.sso.web.model.request.AddRoleRequest;
import com.xu.sso.web.model.request.AddUserRoleRequest;
import com.xu.sso.web.service.PowerService;
import com.xu.sso.web.service.convert.PowerConvert;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class PowerServiceImpl implements PowerService {

    @Autowired
    private RoleDBService roleDBService;
    @Autowired
    private ResourcesDBService resourcesDBService;
    @Autowired
    private AppDBService appDBService;
    @Autowired
    private RedisUtil redisUtil;

    @Override
    public List<Resources> findAllAppRes(String appId) {
        return resourcesDBService.findAllResourcesByApp(appId);
    }

    @Override
    public Resources findResById(Integer id) {
        return resourcesDBService.findResourcesById(id);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public BaseResponse addRes(AddResourcesRequest request) throws SSOException {
        Resources resources = PowerConvert.convert(request);
        int i = resourcesDBService.createResources(resources);
        if (i != 1) {
            log.info(">>>>>>>>>>>>>>>add resources [{}] error...", request.getResPath());
            throw ExceptionUtil.createException(ErrorMessage.AddResourcesError);
        }
        return new BaseResponse();
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public BaseResponse updateRes(Resources resources) throws SSOException {
        int i = resourcesDBService.updateResources(resources);
        if (i != 1) {
            log.info(">>>>>>>>>>>>>>>update resources [{}] error...", resources.getResPath());
            throw ExceptionUtil.createException(ErrorMessage.UpdateResourcesError);
        }
        return new BaseResponse();
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public BaseResponse deleteRes(Integer id) throws SSOException {
        // 删除ResRole
        roleDBService.deleteResourcesRoleByResId(id);
        // 删除Res
        int i = resourcesDBService.deleteResourcesById(id);
        if (i != 1) {
            log.info(">>>>>>>>>>>>>>>delete resources [{}] error...", id);
            throw ExceptionUtil.createException(ErrorMessage.DeleteResourcesError);
        }
        return new BaseResponse();
    }

    @Override
    public BaseResponse refreshRedis(String appId) throws SSOException {
        List<AppPathRole> pathRoles = appDBService.findAppPermissions(appId);
        boolean result = redisUtil.set(SSOConfig.REDIS_SET + appId, pathRoles);
        if (!result) {
            log.info(">>>>>>>>>>>refreshRedis error...");
            throw ExceptionUtil.createException(ErrorMessage.RedisError);
        }
        return new BaseResponse();
    }

    @Override
    public BaseResponse checkRoleExist(String appId, String roleName) throws SSOException {
        boolean result = roleDBService.checkAppRoleExist(appId, roleName);
        if (result) {
            throw ExceptionUtil.createException(ErrorMessage.AppRoleExist);
        }
        return new BaseResponse();
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public BaseResponse addAppRole(AddRoleRequest request) throws SSOException {
        AppRole appRole = PowerConvert.convert(request);
        int i = roleDBService.createAppRole(appRole);
        if (i != 1) {
            throw ExceptionUtil.createException(ErrorMessage.UnknowError);
        }
        return new BaseResponse();
    }

    @Override
    public AppRole findAppRoleById(Integer id) {
        return roleDBService.findAppRoleById(id);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public BaseResponse deleteRoleById(Integer id) throws SSOException {
        // 删除AppUserRole
        roleDBService.deleteAppUserRolesByRoleId(id);
        // 删除ResRole
        roleDBService.deleteResourcesRoleByRoleId(id);
        // 删除AppRole
        int i = roleDBService.deleteAppRoleById(id);
        if (i != 1) {
            throw ExceptionUtil.createException(ErrorMessage.AddAppRoleError);
        }
        return new BaseResponse();
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public BaseResponse updateRole(AppRole appRole) throws SSOException {
        int i = roleDBService.updateAppRole(appRole);
        if (i != 1) {
            throw ExceptionUtil.createException(ErrorMessage.UpdateAppRoleError);
        }
        return new BaseResponse();
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public BaseResponse updateRoleStatus(Integer id, String status) throws SSOException {
        int i = roleDBService.updateAppRoleStatus(id, status);
        if (i != 1) {
            throw ExceptionUtil.createException(ErrorMessage.ChangeAppRoleStatusError);
        }
        return new BaseResponse();
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public BaseResponse addAppUser(String appId, String users) throws SSOException {
        int count, size;
        if (users.contains(",")) {
            String[] us = users.split(",");
            size = us.length;
            count = appDBService.createAppUserList(appId, Arrays.asList(us));
        } else {
            size = 1;
            count = appDBService.createAppUser(appId, users);
        }
        if (count != size) {
            throw ExceptionUtil.createException(ErrorMessage.AddAppUserError);
        }
        return new BaseResponse();
    }

    @Override
    public List<AppRole> findInAppUserRole(String appId, String username) {
        return roleDBService.findInAppRoles(appId, username);
    }

    @Override
    public List<AppRole> findNotInAppUserRole(String appId, String username) {
        return roleDBService.findNotInAppRoles(appId, username);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public BaseResponse addAppUserRole(AddUserRoleRequest request) throws SSOException {
        List<AppRole> appRoles = roleDBService.findInAppRoles(request.getAppId(), request.getUsername());
        List<Integer> oldRoles = appRoles.stream().map(AppRole::getId).collect(Collectors.toList());
        List<Integer> roles = new ArrayList<>();
        if (StringUtils.isNotBlank(request.getRoles())) {
            if (request.getRoles().contains(",")) {
                roles = Arrays.stream(request.getRoles().split(",")).map(Integer::valueOf).collect(Collectors.toList());
            } else {
                roles.add(Integer.valueOf(request.getRoles()));
            }
        }
        Set<Integer> allRoles = new HashSet<>();
        allRoles.addAll(roles);
        allRoles.addAll(oldRoles);
        if (allRoles.size() != roles.size() || allRoles.size() != oldRoles.size()) {
            if (roles.size() > oldRoles.size()) {
                // 添加新角色
                List<Integer> newRoles = roles.stream().filter(t -> !oldRoles.contains(t)).collect(Collectors.toList());
                int count = roleDBService.createAppUserRoles(newRoles, request.getAppId(), request.getUsername());
                if (count != newRoles.size()) {
                    throw ExceptionUtil.createException(ErrorMessage.AddAppUserRolesError);
                }
            } else {
                // 删除老角色
                final List<Integer> roles2 = roles;
                List<Integer> newRoles = oldRoles.stream().filter(t -> !roles2.contains(t)).collect(Collectors.toList());
                int count = roleDBService.deleteAppUserRoles(newRoles, request.getAppId(), request.getUsername());
                if (count != newRoles.size()) {
                    throw ExceptionUtil.createException(ErrorMessage.DeleteAppUserRolesError);
                }
            }
        }
        // 项目leader授权
        if (!request.getLeader().equals(request.getIsLeader())) {
            App app = appDBService.findAppByAppId(request.getAppId());
            int leaderSize = 1;
            if (app.getLeader().contains(";")) {
                leaderSize = app.getLeader().split(";").length;
            }
            if (request.getIsLeader().equals("true")) {
                if (leaderSize >= 3) {
                    throw ExceptionUtil.createException(ErrorMessage.AppLeaderNumMaxError);
                }
                app.setLeader(app.getLeader() + ";" + request.getUsername());
            } else {
                if (leaderSize == 1) {
                    throw ExceptionUtil.createException(ErrorMessage.AppLeaderNumMinError);
                }
                String leader = app.getLeader();
                leader = StringUtils.remove(leader, ";" + request.getUsername());
                leader = StringUtils.remove(leader, request.getUsername() + ";");
                app.setLeader(leader);
            }
            appDBService.updateApp(app);
        }
        return new BaseResponse();
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public BaseResponse addResourcesRole(AddResRoleRequest request) throws SSOException {
        List<AppRole> appRoles = roleDBService.findInResRolesByResId(request.getAppId(), request.getResId());
        List<Integer> oldRoles = appRoles.stream().map(AppRole::getId).collect(Collectors.toList());
        List<Integer> roles = new ArrayList<>();
        if (StringUtils.isNotBlank(request.getRoles())) {
            if (request.getRoles().contains(",")) {
                roles = Arrays.stream(request.getRoles().split(",")).map(Integer::valueOf).collect(Collectors.toList());
            } else {
                roles.add(Integer.valueOf(request.getRoles()));
            }
        }
        Set<Integer> allRoles = new HashSet<>();
        allRoles.addAll(roles);
        allRoles.addAll(oldRoles);
        if (allRoles.size() != roles.size() || allRoles.size() != oldRoles.size()) {
            if (roles.size() > oldRoles.size()) {
                // 添加新角色
                List<Integer> newRoles = roles.stream().filter(t -> !oldRoles.contains(t)).collect(Collectors.toList());
                int count = roleDBService.createResourcesRoles(newRoles, request.getAppId(), request.getResId());
                if (count != newRoles.size()) {
                    throw ExceptionUtil.createException(ErrorMessage.AddResourcesRoleError);
                }
            } else {
                // 删除老角色
                final List<Integer> roles2 = roles;
                List<Integer> newRoles = oldRoles.stream().filter(t -> !roles2.contains(t)).collect(Collectors.toList());
                int count = roleDBService.deleteResourcesRole(newRoles, request.getAppId(), request.getResId());
                if (count != newRoles.size()) {
                    throw ExceptionUtil.createException(ErrorMessage.DeleteResourcesRoleError);
                }
            }
        }
        return new BaseResponse();
    }

    @Override
    public List<AppRole> findInResRole(String appId, Integer resId) {
        return roleDBService.findInResRolesByResId(appId, resId);
    }

    @Override
    public List<AppRole> findNotInResRole(String appId, Integer resId) {
        return roleDBService.findNotInResRolesByResId(appId, resId);
    }
}
